using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;


public class AkWwiseProjectData
{
    private static AkWwiseProjectData _instance;

	public static AkWwiseProjectData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new AkWwiseProjectData();
            }
            
            return _instance;
        }
    } 

	public class ByteArrayWrapper
	{
		public ByteArrayWrapper(byte[] byteArray)
		{
			bytes = byteArray;
		}

		public byte[] bytes;
	}
	public class AkInformation
    {
        public string Name;
        public string Path;
        public List<PathElement> PathAndIcons = new List<PathElement>();
        public int ID; 
		public byte[] Guid = null;
    }
    public class GroupValue : AkInformation
    {
        public List<string> values = new List<string>();
        public List<PathElement> ValueIcons = new List<PathElement>();
        public List<int> valueIDs = new List<int>();

		//Unity can't serialize a list of arrays. So we create a serializable wrapper class for our array 
		public List<ByteArrayWrapper> ValueGuids = new List<ByteArrayWrapper>();
    }
    public class Event : AkInformation
    {
        public float maxAttenuation;
    }
	public class WorkUnit : IComparable
	{
		public WorkUnit(){}

		public WorkUnit(string in_physicalPath)
		{
			PhysicalPath = in_physicalPath;
		}

		public string PhysicalPath;
		public string ParentPhysicalPath;
		public string Guid;       
		
		public int CompareTo( object other )
		{
			WorkUnit otherWwu = other as WorkUnit;

			return PhysicalPath.CompareTo (otherWwu.PhysicalPath);
		}

        //DateTime Objects are not serializable, so we have to use its binary format (64 bit long).
        //But apparently long isn't serializable neither, so we split it into two int
        private int m_lastTimePsrt1 = 0;
        private int m_lastTimePart2 = 0;

        public void SetLastTime(DateTime in_time)
        {
            long timeBin = in_time.ToBinary();

            m_lastTimePsrt1 = (int)timeBin;
            m_lastTimePart2 = (int)(timeBin >> 32);
        }

        public DateTime GetLastTime()
        {
            long timeBin = (long)m_lastTimePart2;
            timeBin <<= 32;
            timeBin |= (uint)m_lastTimePsrt1;

            return DateTime.FromBinary(timeBin);
        }
	}

	public class WorkUnit_CompareByPhysicalPath : IComparer
	{
		int IComparer.Compare(object a, object b)
		{
			WorkUnit wwuA = a as WorkUnit; 
			WorkUnit wwuB = b as WorkUnit;
			
			return wwuA.PhysicalPath.CompareTo (wwuB.PhysicalPath);
		}
	}

    public class AkInformation_CompareByName : IComparer
    {
        int IComparer.Compare(object a, object b)
        {
            AkInformation AkInfA = a as AkInformation;
            AkInformation AkInfB = b as AkInformation;

            return AkInfA.Name.CompareTo(AkInfB.Name);
        }
    }
	public class EventWorkUnit : WorkUnit
	{
		public List<Event> List = new List<Event>();
	}

	public class AkInfoWorkUnit : WorkUnit
	{
		public List<AkInformation> List = new List<AkInformation>();
	}
	public class GroupValWorkUnit : WorkUnit
	{
		public List<GroupValue> List = new List<GroupValue>();
	}

    public class PathElement
    {
        public string ElementName;
        public WwiseObjectType ObjectType;

        public PathElement(string Name, WwiseObjectType objType)
        {
            ElementName = Name;
            ObjectType = objType;
        }
    }


	public enum WwiseObjectType
    {
        // Insert Wwise icons description here
        NONE,
        AUXBUS,
        BUS,
        EVENT,
        FOLDER,
        PHYSICALFOLDER,
        PROJECT,
        SOUNDBANK,
        STATE,
        STATEGROUP,
        SWITCH,
        SWITCHGROUP,
        WORKUNIT,
        GAMEPARAMETER,
        TRIGGER
    }

	//Can't use a list of WorkUnit and cast it when needed because unity will serialize it as 
	//Workunit and all the child class's fields will be deleted
	public List<EventWorkUnit>		EventWwu	= new List<EventWorkUnit>();
	public List<AkInfoWorkUnit> 	AuxBusWwu 	= new List<AkInfoWorkUnit>();
	public List<GroupValWorkUnit>	StateWwu 	= new List<GroupValWorkUnit>();
	public List<GroupValWorkUnit>	SwitchWwu 	= new List<GroupValWorkUnit>();
	public List<AkInfoWorkUnit>		BankWwu		= new List<AkInfoWorkUnit>();
	public List<AkInfoWorkUnit>		RtpcWwu		= new List<AkInfoWorkUnit>();
    public List<AkInfoWorkUnit>     TriggerWwu  = new List<AkInfoWorkUnit>();

	//Contains the path of all items that are expanded in the Wwise picker
	public List<string> ExpandedItems = new List<string> ();

	//An IComparer that enables us to sort work units by their physical path 
    public static WorkUnit_CompareByPhysicalPath s_compareByPhysicalPath = new WorkUnit_CompareByPhysicalPath();

    //An IComparer that enables us to sort AkInformations by their physical name
    public static AkInformation_CompareByName s_compareAkInformationByName = new AkInformation_CompareByName();

    public ArrayList GetWwuListByString(string in_wwuType)
    {
        if (String.Equals(in_wwuType, "Events", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(EventWwu);
        }
        else if (String.Equals(in_wwuType, "States", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(StateWwu);
        }
        else if (String.Equals(in_wwuType, "Switches", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(SwitchWwu);
        }
        else if (String.Equals(in_wwuType, "Master-Mixer Hierarchy", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(AuxBusWwu);
        }
        else if (String.Equals(in_wwuType, "SoundBanks", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(BankWwu);
        }
        else if (String.Equals(in_wwuType, "Game Parameters", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(RtpcWwu);
        }
        else if (String.Equals(in_wwuType, "Triggers", StringComparison.OrdinalIgnoreCase))
        {
            return ArrayList.Adapter(TriggerWwu);
        }

        return null;
    }

	public WorkUnit NewChildWorkUnit(string in_wwuType)
	{
		if(String.Equals(in_wwuType, "Events", StringComparison.OrdinalIgnoreCase))
		{
			return new EventWorkUnit();
		}
		else if(String.Equals(in_wwuType, "States", StringComparison.OrdinalIgnoreCase) || String.Equals(in_wwuType, "Switches", StringComparison.OrdinalIgnoreCase))
		{
			return new GroupValWorkUnit();
		}
		else if(String.Equals(in_wwuType, "Master-Mixer Hierarchy", StringComparison.OrdinalIgnoreCase) 
            || String.Equals(in_wwuType, "SoundBanks", StringComparison.OrdinalIgnoreCase) 
            || String.Equals(in_wwuType, "Game Parameters", StringComparison.OrdinalIgnoreCase)
            || String.Equals(in_wwuType, "Triggers", StringComparison.OrdinalIgnoreCase))
		{
			return new AkInfoWorkUnit();
		}

		return null;
	}

	public float GetEventMaxAttenuation(int in_eventID)
    {
		for(int i = 0; i < EventWwu.Count; i++)
		{
			for(int j = 0; j < EventWwu[i].List.Count; j++)
			{
				if(EventWwu[i].List[j].ID.Equals(in_eventID))
					return EventWwu[i].List[j].maxAttenuation;
			}
		}
        return 0.0f;
    }

    public Event FindEvent(Guid guid)
    {
        for (int i = 0; i < EventWwu.Count; i++)
        {
            var e = EventWwu[i].List.Find(x => new Guid(x.Guid).Equals(guid));
            if(e != null)
            {
                return e;
            }
        }
        return null;
    }

    public Event FindEvent(string eventName)
    {
        for (int i = 0; i < EventWwu.Count; i++)
        {
            var e = EventWwu[i].List.Find(x => x.Name.Equals(eventName));
            if(e != null)
            {
                return e;
            }
        }
        return null;
    }

    public void Reset()
    {
        EventWwu = new List<EventWorkUnit>();
		StateWwu = new List<GroupValWorkUnit>();
		SwitchWwu = new List<GroupValWorkUnit>();
        BankWwu = new List<AkInfoWorkUnit>();
		AuxBusWwu = new List<AkInfoWorkUnit>();
        RtpcWwu = new List<AkInfoWorkUnit>();
        TriggerWwu = new List<AkInfoWorkUnit>();
    }
}
